package com.wm.blog_common.util.excel;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @class_name: PoiMergeExcelTask
 * @description:
 * @author: wm_yu
 * @create: 2019/09/20
 **/
public class PoiMergeExcelTask implements Runnable {

    private final static Logger logger = LoggerFactory.getLogger(PoiMergeExcelTask.class);

    private Sheet sheet;
    private List<?> dataList;
    private List<Field> fields;
    private int rowIndex;
    private CountDownLatch latch;
    private CellStyle cellStyle;
    private List<String> tempList;
    /**
     * 不需要合并行的字段
     */
    private List<Field> notMergeList;

    private static ReentrantLock lock = new ReentrantLock();

    public PoiMergeExcelTask(Sheet sheet, List<?> dataList, List<Field> fields, int rowIndex, CountDownLatch latch, CellStyle cellStyle, List<String> tempList, List<Field> notMergeList) {
        this.sheet = sheet;
        this.dataList = dataList;
        this.fields = fields;
        this.rowIndex = rowIndex;
        this.latch = latch;
        this.cellStyle = cellStyle;
        this.tempList = tempList;
        this.notMergeList = notMergeList;
    }

    @Override
    public void run() {
        try {
            for (Object obj : dataList) {
                Row rowData = getRow(sheet, rowIndex);
                if(!Optional.ofNullable(rowData).isPresent()){
                    break;
                }
                List<Row> rowList = new ArrayList<>();
                List<T> voList = new ArrayList<>();
                //循环插入数据
                for (int i = 0; i < fields.size(); i++) {
                    Cell newCell = rowData.createCell(i);
                    Field field = fields.get(i);
                    field.setAccessible(true);
                    Object fieldValue = null;
                    //排除掉list泛型中的字段
                    if(!tempList.contains(field.toGenericString())){
                        fieldValue = field.get(obj);
                    }
                    //获取到不需要合并行的数据
                    if(CollectionUtils.isNotEmpty(notMergeList)){
                        voList.clear();
                        voList = new ArrayList<>();
                        Field var = notMergeList.get(0);
                        //获取到list数据,如果有
                        if (List.class.isAssignableFrom(var.getType())) {
                            Type t = var.getGenericType();
                            if (t instanceof ParameterizedType) {
                                ParameterizedType pt = (ParameterizedType) t;
                                var.setAccessible(true);
                                //获取到属性的值的Class对象
                                Class clazz = var.get(obj).getClass();
                                try {
                                    Method m= clazz.getDeclaredMethod("size");
                                    int size = (Integer) m.invoke(var.get(obj));
                                    //遍历list，调用get方法，获取list中的对象实例
                                    for (int j = 0; j < size; j++) {
                                        Method getMethod = clazz.getDeclaredMethod("get",int.class);
                                        if(!getMethod.isAccessible()){
                                            getMethod.setAccessible(true);
                                        }
                                        T invoke = (T) getMethod.invoke(var.get(obj),j);
                                        voList.add(invoke);
                                    }
                                } catch (Exception e) {
                                    logger.error("refelect gain " + var.toGenericString() + " error....{}",e);
                                }
                            }
                        }
                        //初始化额外的行
                        Row noMergeRow = null;
                        for (int k = 0; k < voList.size(); k ++){
                            //空白行 防止创建不同的行
                            if(rowList.size() != voList.size()){
                                noMergeRow = (0 == k) ? rowData:sheet.createRow(rowIndex + k);
                                rowList.add(noMergeRow);
                            }
                        }
                        for (int k = 0; k < voList.size(); k ++) {
                            if(tempList.contains(field.toGenericString())){
                                //不需要合并的具体的数据
                                T vo = voList.get(k);
                                field.setAccessible(true);
                                try {
                                    Object o = field.get(vo);
                                    String s = FieldReflectionUtil.formatValue(field,o);
                                    Cell noMergeCell = (0 == k) ? newCell:rowList.get(k).createCell(i);
                                    noMergeCell.setCellValue(s);
                                    noMergeCell.setCellStyle(cellStyle);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                        if(!tempList.contains(field.toGenericString())){
                            //达到合并单元格的条件
                            if(voList.size() > 1){
                                sheet.addMergedRegion(new CellRangeAddress(rowIndex,rowIndex + voList.size() - 1,i,i));
                            }
                            String fieldValueString = FieldReflectionUtil.formatValue(field,fieldValue);
                            newCell.setCellValue(fieldValueString);
                            newCell.setCellStyle(cellStyle);
                        }
                    }else{
                        //没有合并行的数据
                        String fieldValueString = FieldReflectionUtil.formatValue(field,fieldValue);
                        newCell.setCellStyle(cellStyle);
                        newCell.setCellValue(fieldValueString);
                    }
                }
                rowIndex = (0 == voList.size()) ? rowIndex + 1:rowIndex + voList.size();
            }
        } catch (IllegalAccessException e) {
            logger.error("填充excel行数据异常:{}",e.getMessage(),e);
        } finally {
            Optional.ofNullable(latch).ifPresent(x -> {
                x.countDown();
            });
        }
    }

    /**
     * 获取行,加锁
     * @param sheet
     * @param rowIndex
     * @return
     */
    private static Row getRow(Sheet sheet,int rowIndex) {
        lock.lock();
        Row row = null;
        try {
            row = sheet.createRow(rowIndex);
        } catch (Exception e) {
            logger.error("获取excel行对象异常:{}",e.getMessage(),e);
        } finally {
            lock.unlock();
        }
        return row;
    }
}
